package meter

import (
	"context"
	"fmt"
	"net/url"
	"time"

	"gitee.com/spume/toolkit/utils/slices"
	"github.com/gogf/gf/v2/encoding/gjson"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
)

// ClientInterface defines the interface that both real and mock clients must implement
type ClientInterface interface {
	DoRequest(ctx context.Context, method, endpoint string, data any) (*gjson.Json, error)
}

// Service provides high-level meter API operations.
type Service struct {
	client ClientInterface
}

// NewService creates a new meter service with the provided client.
func NewService(client ClientInterface) *Service {
	return &Service{
		client: client,
	}
}

// Meter retrieves a list of all smart meter devices
// This method calls the /meter API endpoint and returns all device information
func (s *Service) Meter(ctx context.Context, req *MeterListRequest) (*MeterListData, error) {
	if req == nil {
		req = &MeterListRequest{}
	}

	// Validate request (no validation needed for empty request)
	if err := req.Validate(); err != nil {
		return nil, fmt.Errorf("invalid request: %v", err)
	}

	// Make API request to get all devices
	gjsonResp, err := s.client.DoRequest(ctx, "GET", "/meter", nil)
	if err != nil {
		return nil, err
	}

	// Simple direct JSON unmarshaling - the most straightforward approach
	var response MeterListResponse

	err = gjsonResp.Scan(&response)
	if err != nil {
		return nil, fmt.Errorf("failed to parse JSON response: %v", err)
	}

	return response.Data, nil
}

// EleControl performs electrical control operations on smart meter devices
// This method calls the /ele_control API endpoint with POST method and query parameters
// EleControl 对智能电表设备执行电气控制操作
// 此方法使用POST方法和查询参数调用/ele_control API端点
func (s *Service) EleControl(ctx context.Context, req *EleControlRequest) (*EleControlResponse, error) {
	if req == nil {
		return nil, fmt.Errorf("request cannot be nil")
	}

	// Validate request parameters
	if err := req.Validate(); err != nil {
		return nil, fmt.Errorf("invalid request: %v", err)
	}

	// Log the control operation for audit trail
	g.Log().Infof(ctx, "Executing electrical control operation: device=%s, cid=%s, operation=%s",
		req.Address, req.CID, req.DBType.String())

	// Construct endpoint with properly encoded query parameters
	endpoint := fmt.Sprintf("/ele_control?address=%s&cid=%s&dbType=%s",
		url.QueryEscape(req.Address),
		url.QueryEscape(req.CID),
		url.QueryEscape(string(req.DBType)))

	// Make API request with POST method
	gjsonResp, err := s.client.DoRequest(ctx, "POST", endpoint, nil)
	if err != nil {
		g.Log().Errorf(ctx, "API request failed: %v", err)
		return nil, fmt.Errorf("API request failed: %v", err)
	}

	// Parse JSON response
	var response EleControlResponse
	err = gjsonResp.Scan(&response)
	if err != nil {
		g.Log().Errorf(ctx, "Failed to parse JSON response: %v", err)
		return nil, fmt.Errorf("failed to parse JSON response: %v", err)
	}

	// Set timestamp if not provided by API
	if response.Timestamp == "" {
		response.Timestamp = time.Now().Format(time.RFC3339)
	}

	// Set success flag based on response code
	response.Success = (response.Code == 200 || response.Code == 0)

	// Check API response code
	if !response.Success {
		g.Log().Errorf(ctx, "API error (code %d): %s", response.Code, response.Message)
		return &response, fmt.Errorf("API error (code %d): %s", response.Code, response.Message)
	}

	// Log successful operation
	g.Log().Infof(ctx, "Electrical control operation successful: device=%s, operation=%s",
		req.Address, req.DBType.String())

	return &response, nil
}

// EleOpenAccount performs electrical meter account opening operations
// This method calls the /ele_open_account API endpoint with POST method and query parameters
// EleOpenAccount 执行电表开户操作
// 此方法使用POST方法和查询参数调用/ele_open_account API端点
func (s *Service) EleOpenAccount(ctx context.Context, req *EleOpenAccountRequest) (*EleOpenAccountResponse, error) {
	if req == nil {
		return nil, fmt.Errorf("request cannot be nil")
	}

	// Validate request parameters
	if err := req.Validate(); err != nil {
		return nil, fmt.Errorf("invalid request: %v", err)
	}

	// Log the account opening operation for audit trail
	g.Log().Infof(ctx, "Executing electrical meter account opening operation: device=%s, cid=%s, accountId=%s, money=%s, price=%s",
		req.Address, req.CID, req.AccountId, req.Money, req.Price)

	// Construct endpoint with properly encoded query parameters
	endpoint := fmt.Sprintf("/ele_open_account?address=%s&cid=%s&accountId=%s&money=%s&price=%s",
		url.QueryEscape(req.Address),
		url.QueryEscape(req.CID),
		url.QueryEscape(req.AccountId),
		url.QueryEscape(req.Money),
		url.QueryEscape(req.Price))

	// Make API request with POST method
	gjsonResp, err := s.client.DoRequest(ctx, "POST", endpoint, nil)
	if err != nil {
		g.Log().Errorf(ctx, "API request failed: %v", err)
		return nil, fmt.Errorf("API request failed: %v", err)
	}

	// Parse JSON response
	var response EleOpenAccountResponse
	err = gjsonResp.Scan(&response)
	if err != nil {
		g.Log().Errorf(ctx, "Failed to parse JSON response: %v", err)
		return nil, fmt.Errorf("failed to parse JSON response: %v", err)
	}

	// Set open time if not provided by API
	if response.OpenTime == "" {
		response.OpenTime = time.Now().Format(time.RFC3339)
	}

	// Set success flag based on response code
	response.Success = (response.Code == 200 || response.Code == 0)

	// Check API response code
	if !response.Success {
		g.Log().Errorf(ctx, "API error (code %d): %s", response.Code, response.Message)
		return &response, fmt.Errorf("API error (code %d): %s", response.Code, response.Message)
	}

	// Log successful operation
	g.Log().Infof(ctx, "Electrical meter account opening operation successful: device=%s, accountId=%s, initialBalance=%s",
		req.Address, req.AccountId, response.InitialBalance)

	return &response, nil
}

// EleReset performs electrical meter reset operations
// This method calls the /ele_reset API endpoint with POST method and query parameters
// EleReset 执行电表重置操作
// 此方法使用POST方法和查询参数调用/ele_reset API端点
func (s *Service) EleReset(ctx context.Context, req *EleResetRequest) (*EleResetResponse, error) {
	if req == nil {
		return nil, fmt.Errorf("request cannot be nil")
	}

	// Validate request parameters
	if err := req.Validate(); err != nil {
		return nil, fmt.Errorf("invalid request: %v", err)
	}

	// Log the reset operation for audit trail
	g.Log().Infof(ctx, "Executing electrical meter reset operation: device=%s, cid=%s, accountId=%s",
		req.Address, req.CID, req.AccountId)

	// Construct endpoint with properly encoded query parameters
	endpoint := fmt.Sprintf("/ele_reset?address=%s&cid=%s&accountId=%s",
		url.QueryEscape(req.Address),
		url.QueryEscape(req.CID),
		url.QueryEscape(req.AccountId))

	// Make API request with POST method
	gjsonResp, err := s.client.DoRequest(ctx, "POST", endpoint, nil)
	if err != nil {
		g.Log().Errorf(ctx, "API request failed: %v", err)
		return nil, fmt.Errorf("API request failed: %v", err)
	}

	// Parse JSON response
	var response EleResetResponse
	err = gjsonResp.Scan(&response)
	if err != nil {
		g.Log().Errorf(ctx, "Failed to parse JSON response: %v", err)
		return nil, fmt.Errorf("failed to parse JSON response: %v", err)
	}

	// Set reset time if not provided by API
	if response.ResetTime == "" {
		response.ResetTime = time.Now().Format(time.RFC3339)
	}

	// Set success flag based on response code
	response.Success = (response.Code == 200 || response.Code == 0)

	// Check API response code
	if !response.Success {
		g.Log().Errorf(ctx, "API error (code %d): %s", response.Code, response.Message)
		return &response, fmt.Errorf("API error (code %d): %s", response.Code, response.Message)
	}

	// Log successful operation
	g.Log().Infof(ctx, "Electrical meter reset operation successful: device=%s, accountId=%s, status=%s",
		req.Address, req.AccountId, response.AccountStatus)

	return &response, nil
}

// EleRecharge performs electrical meter recharge operations
// This method calls the /ele_recharge API endpoint with POST method and query parameters
// EleRecharge 执行电表充值操作
// 此方法使用POST方法和查询参数调用/ele_recharge API端点
func (s *Service) EleRecharge(ctx context.Context, req *EleRechargeRequest) (*EleRechargeResponse, error) {
	if req == nil {
		return nil, fmt.Errorf("request cannot be nil")
	}

	// Validate request parameters
	if err := req.Validate(); err != nil {
		return nil, fmt.Errorf("invalid request: %v", err)
	}

	// Log the recharge operation for audit trail
	g.Log().Infof(ctx, "Executing electrical meter recharge operation: device=%s, cid=%s, accountId=%s, money=%s, count=%s, price=%s",
		req.Address, req.CID, req.AccountId, req.Money, req.Count, req.Price)

	// Construct endpoint with properly encoded query parameters
	endpoint := fmt.Sprintf("/ele_recharge?address=%s&cid=%s&accountId=%s&money=%s&count=%s&price=%s",
		url.QueryEscape(req.Address),
		url.QueryEscape(req.CID),
		url.QueryEscape(req.AccountId),
		url.QueryEscape(req.Money),
		url.QueryEscape(req.Count),
		url.QueryEscape(req.Price))

	// Make API request with POST method
	gjsonResp, err := s.client.DoRequest(ctx, "POST", endpoint, nil)
	if err != nil {
		g.Log().Errorf(ctx, "API request failed: %v", err)
		return nil, fmt.Errorf("API request failed: %v", err)
	}

	// Parse JSON response
	var response EleRechargeResponse
	err = gjsonResp.Scan(&response)
	if err != nil {
		g.Log().Errorf(ctx, "Failed to parse JSON response: %v", err)
		return nil, fmt.Errorf("failed to parse JSON response: %v", err)
	}

	if response.Data != nil && response.Data.ErrMsg != "" {
		return nil, fmt.Errorf("API error: %s", response.Data.ErrMsg)
	}

	return &response, nil
}

// EleWrite performs electrical write operations to smart meter devices
// This method calls the /ele_write API endpoint with POST method and query parameters
func (s *Service) EleWrite(ctx context.Context, req *EleWriteRequest) error {
	if req == nil {
		return fmt.Errorf("request cannot be nil")
	}

	// Validate request parameters
	if err := req.Validate(); err != nil {
		return fmt.Errorf("invalid request: %v", err)
	}

	// Construct endpoint with properly encoded query parameters
	endpoint := fmt.Sprintf("/ele_write?address=%s&cid=%s&dbType=%s&params=%s",
		url.QueryEscape(req.Address),
		url.QueryEscape(req.CID),
		url.QueryEscape(gconv.String(req.DBType)),
		url.QueryEscape(gconv.String(req.Params)))

	// Make API request with POST method
	gjsonResp, err := s.client.DoRequest(ctx, "POST", endpoint, nil)
	if err != nil {
		return fmt.Errorf("API request failed: %v", err)
	}

	// Parse JSON response
	var response EleWriteResponse
	err = gjsonResp.Scan(&response)
	if err != nil {
		return fmt.Errorf("failed to parse JSON response: %v", err)
	}

	// Check API response code
	if response.Code != 200 && response.Code != 0 {
		return fmt.Errorf("API error (code %d): %s", response.Code, response.Message)
	}

	return nil
}

// StatisticEle retrieves electrical meter statistical data
// This method calls the /statisticEle API endpoint with query parameters
func (s *Service) StatisticEle(ctx context.Context, req *StatisticEleRequest) (*StatisticEleData, error) {
	if req == nil {
		return nil, fmt.Errorf("request cannot be nil")
	}

	// Validate request parameters
	if err := req.Validate(); err != nil {
		return nil, fmt.Errorf("invalid request: %v", err)
	}

	// Construct endpoint with properly encoded query parameters
	endpoint := fmt.Sprintf("/statisticEle?timeType=%s&startTime=%s&endTime=%s",
		url.QueryEscape(req.TimeType.String()),
		url.QueryEscape(req.StartTime),
		url.QueryEscape(req.EndTime))

	// Make API request with GET method
	gjsonResp, err := s.client.DoRequest(ctx, "GET", endpoint, nil)
	if err != nil {
		return nil, fmt.Errorf("API request failed: %v", err)
	}

	// Parse JSON response
	var response StatisticEleResponse
	err = gjsonResp.Scan(&response)
	if err != nil {
		return nil, fmt.Errorf("failed to parse JSON response: %v", err)
	}

	// Check API response code
	if response.Code != 200 && response.Code != 0 {
		return nil, fmt.Errorf("API error (code %d): %s", response.Code, response.Message)
	}

	if !g.IsEmpty(response.Data) {

		for _, meterStatistic := range response.Data.Data {
			for i := range meterStatistic {
				meterStatistic[i].D = slices.PadSliceWithDefault(meterStatistic[i].D, 5, 0)
				meterStatistic[i].S = slices.PadSliceWithDefault(meterStatistic[i].S, 5, 0)
				meterStatistic[i].E = slices.PadSliceWithDefault(meterStatistic[i].E, 5, 0)
			}
		}
	}

	return response.Data, nil
}

// EleMeterState retrieves current state information for electrical meters
// This method calls the /eleMeterState API endpoint with optional address filtering
// EleMeterState 获取电表的当前状态信息
// 此方法调用/eleMeterState API端点，支持可选的地址过滤
func (s *Service) EleMeterState(ctx context.Context, req *EleMeterStateRequest) (*EleMeterStateData, error) {
	if req == nil {
		req = &EleMeterStateRequest{}
	}

	// Validate request parameters
	if err := req.Validate(); err != nil {
		return nil, fmt.Errorf("invalid request: %v", err)
	}

	// Construct endpoint with optional address query parameter
	endpoint := "/eleMeterState"

	// Make API request with GET method
	gjsonResp, err := s.client.DoRequest(ctx, "GET", endpoint, g.Map{})
	if err != nil {
		g.Log().Errorf(ctx, "API request failed: %v", err)
		return nil, fmt.Errorf("API request failed: %v", err)
	}

	// Parse JSON response
	var response EleMeterStateResponse
	err = gjsonResp.Scan(&response)
	if err != nil {
		g.Log().Errorf(ctx, "Failed to parse JSON response: %v", err)
		return nil, fmt.Errorf("failed to parse JSON response: %v", err)
	}

	// Check API response code
	if response.Code != 200 && response.Code != 0 {
		g.Log().Errorf(ctx, "API error (code %d): %s", response.Code, response.Message)
		return nil, fmt.Errorf("API error (code %d): %s", response.Code, response.Message)
	}

	// Handle empty response data
	if response.Data == nil {
		g.Log().Infof(ctx, "No meter state data returned from API")
		return &EleMeterStateData{
			Data:   []MeterState{},
			Status: 0,
			Total:  0,
		}, nil
	}

	return response.Data, nil
}
